package com.easyooo.framework.configure; import static org.springframework.util.Assert.notNull; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import com.easyooo.framework.support.zookeeper.ZookeeperExpcetion; import com.easyooo.framework.support.zookeeper.ZookeeperTemplate; /** * <p>这是一个统一配置的扫描器,扩展Spring BeanDefinition后置处理器</p> * <p>实现从远程服务器<code><i>zookeeper</i></code>读取统一配置信息并注入到Spring容器中</p> * <p>每个直接子节点都会触发执行器执行,由节点处理器负责完成配置的过程 </p> * * @author Killer */ public class ZookeeperUnifiedConfigurer implements BeanDefinitionRegistryPostProcessor, InitializingBean{ private Logger logger = LoggerFactory.getLogger(getClass()); private static final String CONFIGURATION_PATH = "/configuration"; private String configPath = CONFIGURATION_PATH; private Map<String, NodeExecutor> executorMap; private ZookeeperTemplate zookeeperTemplate; /** * 如果设置了该属性,则不从远程读取,只从本地属性读取配置信息 * 意味着本地必须配置<code>connectionString</code> */ @SuppressWarnings("unused") private boolean debugMode = false; @Override public void postProcessBeanFactory( ConfigurableListableBeanFactory beanFactory) throws BeansException { // do nothing // end } @Override public void afterPropertiesSet() throws Exception { notNull(this.zookeeperTemplate, "Property 'zookeeperTemplate' is required"); notNull(this.executorMap, "ExecutorMap requires at least one element."); } @Override public void postProcessBeanDefinitionRegistry( BeanDefinitionRegistry registry) throws BeansException { List<String> nodes = null; try { nodes = getChildren(this.configPath); List<BeanDefinitionHolder> bdHolder = new ArrayList<>(); for (String node : nodes) { List<BeanDefinitionHolder> tmp = publishNode(node); if(tmp != null){ bdHolder.addAll(tmp); } } for (BeanDefinitionHolder definitionHolder : bdHolder) { registerBeanDefinition(definitionHolder, registry); } if(logger.isDebugEnabled()){ StringBuffer sb = new StringBuffer("["); int counter = 1; for (BeanDefinitionHolder dh : bdHolder) { sb.append(dh.getBeanName()); if(counter ++ != bdHolder.size()){ sb.append(","); } } sb.append("] registered into spring's container."); logger.debug(sb.toString()); } } catch (UnifiedConfigException e) { throw new BeanCreationException("Failed to create bean", e); } } private List<String> getChildren(String configPath)throws UnifiedConfigException{ try { return zookeeperTemplate.getChildren(configPath); } catch (ZookeeperExpcetion e) { throw new UnifiedConfigException("Gets the child nodes of the " + configPath +" path to make mistakes", e); } } protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, registry); } public List<BeanDefinitionHolder> publishNode(String node)throws UnifiedConfigException{ NodeExecutor executor = this.executorMap.get(node); if(executor == null){ logger.warn("Node[ " + node + "] is discarded!"); return null; } List<BeanDefinitionHolder> bdh = executor.doExecute(zookeeperTemplate, node); if(bdh != null && bdh.size() > 0){ return bdh; } return null; } public void setZookeeperTemplate(ZookeeperTemplate zookeeperTemplate) { this.zookeeperTemplate = zookeeperTemplate; } public void setExecutorMap(Map<String, NodeExecutor> executorMap) { this.executorMap = executorMap; } public void setDebugMode(boolean debugMode) { throw new UnsupportedOperationException("Temporary does not support the debug mode"); } }